#pragma once
#include "LockGuard.hpp"
#include "Log.hpp"
#include "Thread.hpp"
#include <cerrno>
#include<iostream>
#include <pthread.h>
#include<vector>
#include<queue>
#include<string.h>

const int g_thread_num=5;
template <class T>
class ThreadPool
{
public:
    pthread_mutex_t* getMutex()
    {
        return &_lock;
    }
    void waitCond(){
        pthread_cond_wait(&_cond, &_lock);
    }
    T getTask(){
        T task=task_queue.front();
        task_queue.pop();
        return task;
    }
    bool isEmpty()
    {
        return task_queue.empty();
    }
    static void* routine(void* args)
    {
        ThreadData* td=static_cast<ThreadData*>(args);
        ThreadPool<T>* tp=static_cast<ThreadPool<T>*>(args);
        T task;
        {
            LockGuard lockguard(tp->getMutex());
            while(tp->isEmpty()){
                tp->waitCond();
            }
            task=tp->getTask();
        }
        task(td->_name);
    }
    ThreadPool<T>* getThreadPool(int num=g_thread_num)
    {
        if(_thread_ptr==nullptr)
        {
            LockGuard lockguard(&_mutex);
            if(_thread_ptr==nullptr)
            {
                _thread_ptr=new ThreadPool<T>(num);
            }
        }
        return _thread_ptr;
    }
    void run()
    {
        for(auto& iter:_threads){
            iter->start();
            logMessage(NORMAL, "%d:%s",errno,strerror(errno));
        }
    }
    void pushTask(const T& task)
    {
        LockGuard lockguard(&_mutex);
        task_queue.push(task);
        pthread_cond_signal(&_cond);
    }
    ~ThreadPool(){
        for(auto& iter:_threads){
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_lock);
    }
private:
    ThreadPool(int thread_num=g_thread_num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        for(int i=0;i<thread_num;i++){
            _threads.push_back(new Thread(1,routine,this));
        }
    }
    ThreadPool(const ThreadPool<T>& )=delete;
    ThreadPool<T>& operator=(const ThreadPool<T>&)=delete;
private:
    pthread_mutex_t _lock;
    pthread_cond_t _cond;
    std::vector<Thread*> _threads;
    std::queue<T> task_queue;
    static pthread_mutex_t _mutex;
    static ThreadPool<T>* _thread_ptr;
};